package uy.org.softtech.cssuite.web.controladores;

import static org.springframework.util.Assert.notNull;

import java.util.Locale;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.context.annotation.Configuration;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import uy.org.softtech.cssuite.core.Comando;
import uy.org.softtech.cssuite.core.Controlador;
import uy.org.softtech.cssuite.entidad.cliente.Cliente;
import uy.org.softtech.cssuite.excepciones.EntidadNoEncontradaException;
import uy.org.softtech.cssuite.servicios.ServiciosClientes;
import uy.org.softtech.cssuite.web.modelo.ModeloCliente;

/**
 * Controlador encargado de atender las solicitudes relacionadas a la administración de los clientes de la aplicación.
 * 
 * @author fabian.lobo
 */
@Configuration
@Controller("controlador-clientes")
@ManagedResource(
	objectName = "cssuite:type=Controlador,name=ControladorClientes", 
	description = "Controlador encargado de atender las solicitudes relacionadas a la administración de los clientes de la aplicación.",
	log = true, logFile = "jmx.log", currencyTimeLimit = 15,
	persistPolicy = "OnUpdate", persistPeriod = 200
)
public class ControladorClientes extends Controlador {

	private Logger log = Logger.getLogger(getClass());
	
	// Servicios
	@Resource(name = "servicios-clientes" )
	private ServiciosClientes serviciosClientes;
	
	// Comandos
	@Resource(name = "comando-cliente")
	private Comando comandoCliente;
	
	/**
	 * Método para verificar que todos los parámetros han sido seteados correctamente.
	 * 
	 * @author fabian.lobo
	 */
	@PostConstruct
	public void inicializacion(){
		super.inicializacion();
		
		notNull(serviciosClientes(), "La propiedad [serviciosClientes] de [" + getClass().getName() + "] no ha sido establecida.");
		notNull(comandoCliente(), "La propiedad [comandoCliente] de [" + getClass().getName() + "] no ha sido establecida.");
		
		log.info("Controlador encargado de atender las solicitudes relacionadas a la administración de los clientes de la aplicación ha sido inicializado.");
	}
	
	/* 
	 * ---------------------------------------
	 * --------   CREAR CLIENTE    -----------
	 * ---------------------------------------
	 */
	/**
	 * Retorna la página para crear un nuevo cliente.
	 * 
	 * @author fabian.lobo
	 */
	@RequestMapping(method = RequestMethod.GET, value = "clientes.do", params = {"accion=CREAR"})
	@Secured(value = {"ROLE_CREAR_CLIENTE"})
	public ModelAndView solicitaCrearUsuario(@ModelAttribute(value = "modeloCliente") ModeloCliente modelo) {
		return new ModelAndView("clientes/creacion");
	}
	
	/**
	 * Procesa la solicitud de crear un nuevo usuario.
	 * 
	 * @author fabian.lobo
	 */
	@RequestMapping(method = RequestMethod.POST, value = "clientes.do", params = {"accion=CREAR"})
	@Secured(value = {"ROLE_CREAR_USUARIO"})
	public ModelAndView procesaCreacionCliente(Locale locale, @ModelAttribute(value = "modeloCliente") ModeloCliente modelo, BindingResult errores) {
		ModelAndView respuesta = new ModelAndView("clientes/creacion");
		
		modelo.setLocale(locale);
		try {
			boolean ejecutado = comandoCliente().ejecutar(modelo, errores);
			if(ejecutado) {
				//Mostramos mensaje al usuario
				respuesta.setViewName("inicio");
				String mensaje = fuenteMensajes().getMessage("mensaje.datosGuardados", null, "Los datos han sido guardados correctamente.", locale);
				mostrarMensajeInformacion(respuesta, mensaje, false, null);
			}
		} catch (Exception e) {
			log.error(e);
			registrarErrorGeneral(errores, locale);
		}		
		return respuesta;
	}
	
	/* 
	 * ---------------------------------------
	 * -------   ACTUALIZAR CLIENTE   --------
	 * ---------------------------------------
	 */
	/**
	 * Retorna la página para el despliegue y/o actualización de la información de un cliente.
	 * 
	 * @param modelo - Entidad encargada de contener los datos ingresados y mostrados en la página
	 * @author fabian.lobo
	 */
	@RequestMapping(method = RequestMethod.GET, value = "clientes.do", params = {"accion=ACTUALIZAR", "id"})
	@Secured(value = {"ROLE_VER_CLIENTES", "ROLE_ACTUALIZAR_CLIENTE"})
	public ModelAndView solicitaInformacionUsuario(@ModelAttribute(value = "modeloCliente") ModeloCliente modelo) {
		try {
			Cliente cliente = serviciosClientes().buscarCliente(modelo.getId());
			modelo.inicializaModelo(cliente);
			switch(cliente.getTipo()) {
			case PERSONA:
				return new ModelAndView("clientes/persona");
			case EMPRESA:
				return new ModelAndView("clientes/empresa");
			}			
		} catch (EntidadNoEncontradaException e) {
			log.error(e);
		}
		return new ModelAndView("redirect:inaccesible.do");
	}
	
	/**
	 * Procesa la solicitud de actualizar la información de un cliente.
	 * 
	 * @author fabian.lobo
	 */
	@RequestMapping(method = RequestMethod.POST, value = "clientes.do", params = {"accion=ACTUALIZAR", "id"})
	@Secured(value = {"ROLE_ACTUALIZAR_CLIENTE"})
	public ModelAndView procesaActualizacionUsuario(Locale locale, @ModelAttribute(value = "modeloCliente") ModeloCliente modelo, BindingResult errores) {
		ModelAndView respuesta = new ModelAndView();
		
		try {
			Cliente cliente = serviciosClientes().buscarCliente(modelo.getId());
			switch(cliente.getTipo()) {
			case PERSONA:
				respuesta.setViewName("clientes/persona");
				break;
			case EMPRESA:
				respuesta.setViewName("clientes/empresa");
				break;
			}
		} catch (EntidadNoEncontradaException e) {
			log.error(e);
		}
		
		modelo.setLocale(locale);
		try {
			boolean ejecutado = comandoCliente().ejecutar(modelo, errores);
			if(ejecutado) {
				//Mostramos mensaje al usuario
				String mensaje = fuenteMensajes().getMessage("mensaje.datosActualizados", null, "Los datos han sido actualizados correctamente.", locale);
				mostrarMensajeInformacion(respuesta, mensaje, false, null);
			}
		} catch (Exception e) {
			log.error(e);
			registrarErrorGeneral(errores, locale);
		}		
		return respuesta;
	}
	
	/*
	 *  GETTERS
	 */
	public ServiciosClientes serviciosClientes() {
		return serviciosClientes;
	}
	public Comando comandoCliente() {
		return comandoCliente;
	}
}
